
#ifndef	CG_PROGRAM
#define	CG_PROGRAM

#ifdef	_WIN32
	#include	<windows.h>

	#pragma	warning (disable:4786)
#endif

#include	<string>

using namespace std;

#include	<GL/gl.h>
#include	"cgGL.h"
#include    "Interfaces/IShader.h"


namespace gengine
{
	namespace kernel
	{
class	CgProgram:public IShaderProgram
{
protected:
	static	CGcontext	context;
	static	CGprofile	vertexProfile;
	static	CGprofile	fragmentProfile;

	CGprogram	program;
	int			type;
	string		listing;
	string		errorDesc;

public:
	
	CgProgram  ( );
	~CgProgram ();
	ShaderProgramType  GetProgramType() const 
	{
		return CG_SHADER;
	}
	bool	Load ( int theType ,const char * fileName );

	const string&	GetListing () const
	{
		return listing;
	}

	const string&	GetErrorDescription () const
	{
		return errorDesc;
	}

	bool	IsVertex () const
	{
		return type == CgVertexProgram;
	}

	bool	IsFragment () const
	{
		return type == CgFragmentProgram;
	}

	CGprofile	GetProfile () const
	{
		return IsVertex () ? vertexProfile : fragmentProfile;
	}

	CGparameter	ParameterForName ( const char * name ) const
	{
		return cgGetNamedParameter ( program, name );
	}

	bool	SetTexture ( const char * name, unsigned texId )
	{
		CGparameter param = ParameterForName ( name );

		if ( !param )
			return false;

		cgGLSetTextureParameter ( param, texId );

		return true;
	}

	bool	 SetConstant  ( const char * name, const Vector4D& value )
	{
		CGparameter param = ParameterForName ( name );

		if ( !param )
			return false;

		cgGLSetParameter4f ( param, value.x, value.y, value.z, value.w );

		return true;
	}

	bool        SetConstant  ( const char * name, const Vector3D& value  )
	{
		CGparameter param = ParameterForName ( name );

		if ( !param )
			return false;

		cgGLSetParameter3f ( param, value.x, value.y, value.z);

		return true;
	}

	bool        SetConstant  ( const char * name, const Vector2D& value  )
	{
		CGparameter param = ParameterForName ( name );

		if ( !param )
			return false;

		cgGLSetParameter2f ( param, value.x, value.y);

		return true;
	}
	
	  bool        SetConstant  ( const char * name, float value            ) 
	 {
		  CGparameter param = ParameterForName ( name );
		 if ( !param )
			return false;

		cgGLSetParameter1f( param, value);

		return true;
	 }

     virtual bool        SetConstant  ( const char * name, const Matrix4x4& value )
	 {
		   CGparameter param = ParameterForName ( name );
		 if ( !param )
			return false;

		cgGLSetMatrixParameterfr( param, value[0]);
		

		return true;
	 }

	 bool        SetConstant  ( const char * name, const Matrix3D&  value )
	 {
		  CGparameter param = ParameterForName ( name );
		 if ( !param )
			return false;

		cgGLSetMatrixParameterfr( param, value[0]);
		

		return true;
	 }

	  bool        SetConstant  ( const char * name, float value [16]       )
	  {
		    CGparameter param = ParameterForName ( name );
		 if ( !param )
			return false;

		cgGLSetMatrixParameterfr( param, value);
		

		return true;
	  }

	   virtual bool        SetConstant  ( const char * name, int value       )
	   {
		   return true;
	   }
	
	bool	SetVector ( CGparameter param, const Vector4D& value )
	{
		if ( !param )
			return false;

		cgGLSetParameter4f ( param, value.x, value.y, value.z, value.w );

		return true;
	}

	bool	Enable  ()
	{
		cgGLEnableProfile ( GetProfile () );

		return true;
	}

	bool	Disable ()
	{
		cgGLDisableProfile ( GetProfile () );

		return true;
	}

	const CGprogram const &GetProgramObject() const
	{
		return program;
	}
	bool	Bind ()
	{
		cgGLBindProgram ( program );

		return true;
	}

	bool	Unbind ()
	{
		cgGLBindProgram ( 0 );

		return true;
	}

	void	SetParameter ( CGparameter param, float x )
	{
		cgGLSetParameter1f ( param, x );
	}

	void	SetParameter ( CGparameter param, const Vector2D& v )
	{
		cgGLSetParameter2fv ( param, v );
	}

	void	SetParameter ( CGparameter param, const Vector3D& v )
	{
		cgGLSetParameter3fv ( param, v );
	}

	void	SetParameter ( CGparameter param, const Vector4D& v )
	{
		cgGLSetParameter4fv ( param, v );
	}

	void	SetMatrixParameter ( CGparameter param, CGGLenum matrix, CGGLenum transform )
	{
		cgGLSetStateMatrixParameter ( param, matrix, transform );
	}

	enum CgProgramType
	{
		CgVertexProgram   = 1,
		CgFragmentProgram = 2
	};

protected:
	bool	CheckCgError ();
};
}
}
#endif
